/**
 * 权限工具
 * @author luguoxiang
 * @date 2021-09-07
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
import { KeyEnum } from '../enums';
import { cache, closeSse, closeWebSocket } from '..';
import { storage } from './storage';
import { baseURL } from '@/config/global';
import { useAccountStore } from '@/store';
import xhr from '@/soar/utils/api/xhr';

const { ACCESS_TOKEN, REFRESH_TOKEN } = KeyEnum;

/**
 * 创建实例
 */
const instance = xhr.create({
  baseURL,
  timeout: 60000,
  headers: { 'Content-Type': 'application/json;' },
});

/**
 * 登录
 * @param res
 */
export function signin(res: { accessToken: string; refreshToken: string }): void {
  cache.put(ACCESS_TOKEN, res.accessToken, 60);
  storage.put(ACCESS_TOKEN, res.accessToken, new Date(Number(res.accessToken.split('.')[1])));
  storage.put(REFRESH_TOKEN, res.refreshToken, new Date(Number(res.refreshToken.split('.')[1])));
}

/**
 * 登出
 */
export function signout(): void {
  try {
    closeWebSocket();
    closeSse();
  } finally {
    storage.remove(ACCESS_TOKEN);
    storage.remove(REFRESH_TOKEN);
    cache.remove(ACCESS_TOKEN);
  }
}

/**
 * 获取token
 * @returns {string}
 */
// eslint-disable-next-line consistent-return
export function getToken(): string | undefined {
  return cache.compute(ACCESS_TOKEN, () => storage.get(ACCESS_TOKEN), 60);
}

/**
 * 获取刷新token
 * @returns {*|void}
 */
export function getRefreshToken(): string {
  return storage.get(REFRESH_TOKEN);
}

export function loadToken(): Promise<{ reload: boolean; token: string }> {
  const token = getToken();
  if (token) {
    return Promise.resolve({ reload: false, token });
  }
  const refreshToken = getRefreshToken();
  if (refreshToken) {
    return instance
      .get('/system/login/refreshToken', { params: { refreshToken } })
      .then((res: any) => {
        res = res.data.data;
        signin(res);
        return { reload: true, token: res.accessToken };
      })
      .catch((err: any) => {
        signout();
        return err;
      });
  }
  return Promise.reject();
}

/**
 * 将权限模式转换为正则
 * @param pattern 匹配模式
 */
export function permitToReg(pattern: string): RegExp {
  pattern = pattern
    .replace(/\*\*/, '\\S{0,}')
    .replace(/\*/, '[^/]{0,}')
    .replace(/\?/, '[^/]{1,1}')
    .replace(/\./, '\\.');
  return new RegExp(`^${pattern}$`);
}

/**
 * 路径匹配器
 * @param pattern 匹配模式
 * @param paths 路径
 * @returns {boolean}
 */
export function antPathMatcher(pattern: string, paths: string[]): boolean {
  const reg = permitToReg(pattern);
  for (const path of paths) {
    if (reg.test(path)) {
      return true;
    }
  }
  return false;
}

class Modifiers {
  /**
   * 必须匹配所有指定权限
   */
  all?: boolean;

  /**
   * 排除指定权限(相当于取反)
   */
  exclude?: boolean;

  /**
   * 验证超级管理员权限
   */
  admin?: boolean;
}

export function auth(...codes) {
  const { permits } = useAccountStore();
  for (const permit of permits) {
    const reg = permitToReg(permit);
    for (const path of codes) {
      if (reg.test(path)) {
        return true;
      }
    }
  }
  return false;
}

/**
 * 权限校验，用户拥有指定权限结果为真
 * @param {string|array<string>} params 指定权限
 * @param {Modifiers} modifiers  修饰符：
 *    all：必须匹配所有指定权限
 *    exclude：排除指定权限(相当于取反)
 *    admin：验证超级管理员权限
 * @returns {boolean}
 */
function permit(
  params: string | string[],
  modifiers: Modifiers = { all: false, exclude: false, admin: false },
): boolean {
  // 是否是超级管理员
  if (!modifiers.admin && admin()) {
    return true;
  }
  // 参数处理
  const TRUE = !modifiers.exclude;
  const FALSE = !TRUE;
  const { permits } = useAccountStore();
  if (!permits) {
    return false;
  }
  if (typeof params === 'string') {
    params = params.split(',');
  } else if (!Array.isArray(params)) {
    return FALSE;
  }
  // 匹配所有
  if (modifiers.all) {
    for (const a of permits) {
      let flag = true;
      if (antPathMatcher(a, params)) {
        flag = FALSE;
        break;
      }
      if (flag && !modifiers.exclude) {
        return FALSE;
      }
    }
    return TRUE;
  }
  // 匹配任意
  for (const a of permits) {
    if (antPathMatcher(a, params)) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * 角色权限，用户拥有指定角色结果为真
 * @param {string|array<string>} params 指定角色
 * @param {object} modifiers 修饰符：
 *    all：必须匹配所有指定角色
 *    exclude：排除指定角色(相当于取反)
 *    admin：验证超级管理员权限
 * @returns {boolean}
 */
function role(
  params: string | string[],
  modifiers: Modifiers = { all: false, exclude: false, admin: false },
): boolean {
  // 是否是超级管理员
  if (!modifiers.admin && admin()) {
    return true;
  }
  // 参数处理
  const TRUE = !modifiers.exclude;
  const FALSE = !TRUE;
  const { roles } = useAccountStore();
  if (!roles) {
    return false;
  }
  if (typeof params === 'string') {
    params = params.split(',');
  } else if (!Array.isArray(params)) {
    return false;
  }
  // 匹配所有
  if (modifiers.all) {
    for (const role of params) {
      if (!roles.includes(role)) {
        return false;
      }
    }
    return TRUE;
  }
  // 匹配任意
  for (const role of params) {
    if (roles.includes(role)) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * 判断是否是指定用户类型
 * @param params 指定用户类型
 * @param {object} modifiers 修饰符：
 *    exclude：排除指定用户类型(相当于取反)
 *    admin：验证超级管理员权限
 * @returns {boolean}
 */
function userType(params: string | string[], modifiers: Modifiers = { exclude: false, admin: false }): boolean {
  // 是否是超级管理员
  if (!modifiers.admin && admin()) {
    return true;
  }
  // 参数处理
  const TRUE = !modifiers.exclude;
  const FALSE = !TRUE;
  if (typeof params === 'string') {
    params = params.split(',');
  } else if (!Array.isArray(params)) {
    return FALSE;
  }
  // 匹配用户类型
  const { user } = useAccountStore();
  const userType = user?.userType;
  for (const p of params) {
    // @ts-ignore
    // eslint-disable-next-line eqeqeq
    if (p == userType) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * 判断是否是超级管理员
 * @param exclude 排除模式（相当于取反），不是超级管理员返回真
 * @returns {any}
 */
function admin(exclude = false): boolean {
  return !exclude && useAccountStore().superAdministrator;
}

export type HasType = 'permit' | 'p' | 'role' | 'r' | 'userType' | 'usertype' | 'ut';

/**
 * 是否拥有指定权限
 * @param type 验证类型：permit、role、userType、admin
 * @param params 指定参数
 * @param {object} modifiers 修饰符：
 *    all：必须匹配所有指定参数，验证类型userType和admin无效
 *    exclude：排除指定参数(相当于取反)
 *    admin：验证超级管理员权限
 * @returns {boolean}
 */
export function has(
  type: HasType,
  params: string | string[],
  modifiers: Modifiers = { all: false, exclude: false, admin: false },
): boolean {
  switch ((type ?? 'p').toLowerCase()) {
    case 'ut':
    case 'usertype':
    case 'user-type':
      return userType(params, modifiers);
    case 'r':
    case 'role':
      return role(params, modifiers);
    default:
      return permit(params, modifiers);
  }
}

has.permit = permit;
has.p = permit;
has.role = role;
has.r = role;
has.userType = userType;
has.ut = userType;
has.admin = admin;
has.a = admin;
